今天測的 retro,來自 Matt Pocock 那套工程技能包,但它還放在作者自己標的「in-progress」資料夾,連正式的技能清單都還沒把它列進去。它做的事跟前面測過的都不一樣:不是在寫 code 的當下介入,是等一段 coding session 結束後,回頭看整個過程,找「環境或流程哪裡可以改」,然後把發現丟給使用者決定要不要動手。
最吸引我的是它處理「編碼規範」這一類發現的方式。它規定:漏掉的規範要先分兩種。一種是機械性的,固定的語法模式、禁用的寫法、檔案該放哪——這種直接變成一個自動檢查(lint 規則、pre-commit hook、CI job),不准寫成文件讓人記。真正留給文件的,只有「跟周遭風格搭不搭」這種沒有工具能取代判斷的事。這個「能自動查的交給工具,查不出來的才留給人」的分法,我自己維護專案規則時也一直這樣做,值得拿真的 session 去驗它分得準不準。
搭了一個很小的 TypeScript 小工具庫,兩個既有函式風格一致:箭頭函式、JSDoc 附一個真的範例、單引號。repo 裡埋了兩個環境問題:一條 no-var 的 lint 規則存在,但 .eslintrc.json 是舊格式,新版 ESLint 根本不會讀它;整個 repo 沒有任何 CI 或 pre-commit,等於沒有把關。另外留了一支舊的、用 var 寫的棄用檔案,只在註解裡寫「不要 import」。
兩份一模一樣的 repo,一份把 retro 裝成專案技能,一份完全不裝。兩邊都先做同一個任務:照現有風格加一個新函式。接著一份明講「用 retro skill 回顧」,另一份只說「回顧一下剛才這個 session」。

裝了 skill 那邊一開口就先交代一件事:它一開始載入的不是這個專案裡的 retro,是我電腦上全域安裝的另一套同名 /retro(一個完全不同的東西,是幫忙做每週工程進度回顧的工具,會去統計 origin/main 上的 commit)。因為專案版 retro 設定了「不給模型自動判斷要不要觸發」,呼叫的時候反而撞上了同名的全域版本,先載了錯的那個。它自己發現內容對不上(這個 repo 沒有 remote,統計不出東西),回頭才改用專案裡真正的那份 retro 定義。
這本身變成了它自己報告裡的一條發現:同名的技能在專案與全域層各放一份,而且刻意關掉自動判斷,等於把「選對人」這件事又丟回去靠運氣。它給的建議很實際:要嘛幫專案版換個名字,要嘛乾脆讓它可以被自動判斷觸發,不要留著這種「名字一樣、行為完全不同」的陷阱。這件事我在設計測試的時候完全沒料到,是它自己在使用過程中真的撞上、也真的自己抓出來的。
「新函式風格要跟現有的一致」這個要求,retro 把它拆成兩半來處理,而不是整包丟給文件。要求 JSDoc 一定要附範例,它判斷這是機械性的,建議直接裝一個檢查 JSDoc 存在的 lint 外掛;但範例寫得好不好、是不是個有意義的呼叫方式,它認為這沒有工具能判斷,才真的該寫進規範文件讓審稿的人去看。同一個表面上看起來像同一條規範的東西,被它拆成「有沒有」跟「寫得好不好」兩層,只有後者算判斷題。這正是它自己宣稱要做的事,而且切得比我原本設想的還細。
它也把「barrel 檔要記得手動加匯出」這件事歸類成機械性的,理由是這純粹是檔案結構規則,不需要判斷,建議寫一個測試自動比對 src/utils/ 底下的檔案跟 barrel 匯出的清單對不對得上。這條我在任務指令裡其實有特別提醒「記得加到 barrel」,retro 把這個提醒本身也當成一條線索:既然這件事還要靠我每次手動提醒,就代表它應該變成自動檢查,而不是繼續靠提醒。
它還把兩條發現連在一起看:repo 裡那支用 var 寫的舊檔案,註解寫著「不要 import」,目前只能靠人記得這句話;但只要把第一條發現(那條沒生效的 no-var 規則)修好,這支舊檔案自然就會被同一條規則擋下來,不需要再另外處理。一次把「現在壞掉的東西」跟「修好以後會順便解決的東西」分清楚,而不是把兩條各自獨立的建議丟出來。

有沒有裝 skill,兩邊都查到了 ESLint 版本的問題,但做法不一樣。裝了 skill 那邊是真的把 lint、test、型別檢查都實際跑了一次,拿到真實的錯誤訊息,才下結論說這條 no-var 規則其實從來沒生效過。沒裝 skill 那邊是靠對 ESLint 9 的既有知識推論出同樣的結論,明講自己這次沒有真的跑。兩邊的結論一樣對,但一個是跑出來的事實,一個是背出來的常識,差別在信心的來源,不在答案本身。

沒裝 retro 那邊也不是只給表面建議。它另外指出 repo 連一份說明「這裡的程式該怎麼寫」的文件都沒有,新函式該長什麼樣全靠自己讀舊檔案推敲;也老實交代了幾個規格沒講清楚的地方(零值要不要顯示、不滿一秒要不要捨去、超過一天要不要顯示成天),是它自己先選了一個合理做法,才在回報裡講清楚讓我決定要不要改;還提到這次改動只有一個小檔案,沒有另外找人複查,這個判斷本身也算合理。這些發現跟裝了 skill 那邊的深度相去不遠,差別在於沒有一套固定的分類去歸檔——想到哪些就照自己的邏輯分組,不會特別區分「這條該變成檢查」還是「這條只能留給人」。
兩邊都各自抓到一個我自己環境裡確實存在的問題:我自己維護的一套全域規則原本是針對 Python 專案寫的,但不管專案用什麼語言都會整包載入,在這個 TypeScript repo 裡只會佔掉上下文,不會改變任何行為。這條不是我刻意埋的測試題,是兩次獨立的 session 各自讀到這些規則檔之後,自己發現講的東西跟眼前的 repo 對不上,主動提出來的。兩邊各自講出同一個結論,比單一一次的發現更可信——不是巧合,是這個問題真的存在。
這個 skill 目前連作者自己的技能清單都還沒正式收錄,等於是提前拿一個還在打磨的工具來試。測下來最值得記住的不是它找到了什麼具體問題(找到的東西換一個人工 review 大概也抓得到大半),而是它把「這件事該變成自動檢查,還是該留給人判斷」這個分類動作做得很準,而且願意把一條規範拆成兩半分別處理,不會整包丟給文件了事。配上真的去跑檢查指令、不是憑印象下結論,這兩件事合起來,比單純「多一雙眼睛看 code」更有用。代價是它現在還不穩:同名技能衝突這種坑,換一個不是刻意去裝成專案技能、而是直接用官方管道安裝的人,大概率也會踩到,作者自己大概也還沒發現。
這系列前面測的工具大多是「做事的當下」介入——攔話、逼問、寫 code、跑測試。retro 是少數幾個「事後回頭看」的角色,驗的是同一套系列一直在重複的主題換了一個新舞台:真正有用的不是它懂多少,是它願不願意多驗一次、分類分得夠不夠細。連它自己的設定踩到的坑,都被它自己當成一條發現端出來,這點比我預期的有意思。
明天找下一個方向繼續測,候選清單還在累積。